using System.Security.Claims;
using GroupSix.Application.Services;
using GroupSix.Application.Dtos;
using GroupSix.Domain.Services;

namespace GroupSix.Api.Middleware;

/// <summary>
/// 权限验证中间件
/// </summary>
public class PermissionMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger<PermissionMiddleware> _logger;

    public PermissionMiddleware(RequestDelegate next, ILogger<PermissionMiddleware> logger)
    {
        _next = next;
        _logger = logger;
    }

    public async Task InvokeAsync(HttpContext context, PermissionService permissionService, ITokenService tokenService)
    {
        try
        {
            // 跳过不需要权限验证的路径
            if (ShouldSkipPermissionCheck(context.Request.Path))
            {
                await _next(context);
                return;
            }

            // 从请求头获取Token
            var token = GetTokenFromRequest(context);
            if (string.IsNullOrEmpty(token))
            {
                context.Response.StatusCode = 401;
                await context.Response.WriteAsJsonAsync(new { success = false, message = "未提供访问令牌" });
                return;
            }

            // 验证Token
            if (!tokenService.ValidateToken(token))
            {
                context.Response.StatusCode = 401;
                await context.Response.WriteAsJsonAsync(new { success = false, message = "访问令牌无效" });
                return;
            }

            // 从Token中获取用户ID
            var userId = tokenService.GetUserIdFromToken(token);
            if (!userId.HasValue)
            {
                context.Response.StatusCode = 401;
                await context.Response.WriteAsJsonAsync(new { success = false, message = "无法获取用户信息" });
                return;
            }

            // 检查用户是否有访问当前路径的权限
            var hasPermission = await CheckPathPermissionAsync(permissionService, userId.Value, context.Request.Path);
            if (!hasPermission)
            {
                context.Response.StatusCode = 403;
                await context.Response.WriteAsJsonAsync(new { success = false, message = "权限不足，无法访问该资源" });
                return;
            }

            // 将用户ID添加到HttpContext中，供后续使用
            context.Items["UserId"] = userId.Value;

            await _next(context);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "权限验证中间件发生错误");
            context.Response.StatusCode = 500;
            await context.Response.WriteAsJsonAsync(new { success = false, message = "服务器内部错误" });
        }
    }

    /// <summary>
    /// 判断是否应该跳过权限检查
    /// </summary>
    /// <param name="path">请求路径</param>
    /// <returns>是否跳过</returns>
    private bool ShouldSkipPermissionCheck(PathString path)
    {
        var skipPaths = new[]
        {
            "/swagger",
            "/api/auth/login",
            "/api/auth/register",
            "/api/user/health",
            "/api/permission/check", // 权限检查接口本身不需要权限验证
            "/api/permission/user-permissions",
            "/api/permission/user-menus"
        };

        return skipPaths.Any(skipPath => path.StartsWithSegments(skipPath));
    }

    /// <summary>
    /// 从请求中获取Token
    /// </summary>
    /// <param name="context">HttpContext</param>
    /// <returns>Token字符串</returns>
    private string? GetTokenFromRequest(HttpContext context)
    {
        // 从Authorization头获取
        var authHeader = context.Request.Headers["Authorization"].FirstOrDefault();
        if (!string.IsNullOrEmpty(authHeader) && authHeader.StartsWith("Bearer "))
        {
            return authHeader.Substring("Bearer ".Length);
        }

        // 从查询参数获取
        var tokenFromQuery = context.Request.Query["token"].FirstOrDefault();
        if (!string.IsNullOrEmpty(tokenFromQuery))
        {
            return tokenFromQuery;
        }

        // 从Cookie获取
        var tokenFromCookie = context.Request.Cookies["access_token"];
        if (!string.IsNullOrEmpty(tokenFromCookie))
        {
            return tokenFromCookie;
        }

        return null;
    }

    /// <summary>
    /// 检查用户是否有访问指定路径的权限
    /// </summary>
    /// <param name="permissionService">权限服务</param>
    /// <param name="userId">用户ID</param>
    /// <param name="path">请求路径</param>
    /// <returns>是否有权限</returns>
    private async Task<bool> CheckPathPermissionAsync(PermissionService permissionService, Guid userId, PathString path)
    {
        try
        {
            // 将路径转换为权限标识
            var permissionKey = ConvertPathToPermissionKey(path);
            
            var request = new ValidatePermissionRequestDto
            {
                UserId = userId,
                PermissionKey = permissionKey,
                MenuPath = path.Value
            };

            var (success, message, data) = await permissionService.ValidatePermissionAsync(request);
            
            return success && data?.HasPermission == true;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "检查路径权限时发生错误");
            return false;
        }
    }

    /// <summary>
    /// 将路径转换为权限标识
    /// </summary>
    /// <param name="path">请求路径</param>
    /// <returns>权限标识</returns>
    private string ConvertPathToPermissionKey(PathString path)
    {
        var pathValue = path.Value?.ToLowerInvariant();
        if (string.IsNullOrEmpty(pathValue))
        {
            return string.Empty;
        }

        // 移除开头的/api
        if (pathValue.StartsWith("/api/"))
        {
            pathValue = pathValue.Substring(5);
        }

        // 将路径转换为权限标识格式
        // 例如: /api/role -> role
        // 例如: /api/menu/tree -> menu:tree
        var segments = pathValue.Split('/', StringSplitOptions.RemoveEmptyEntries);
        
        if (segments.Length == 0)
        {
            return string.Empty;
        }

        if (segments.Length == 1)
        {
            return segments[0];
        }

        return $"{segments[0]}:{segments[1]}";
    }
}

/// <summary>
/// 权限中间件扩展方法
/// </summary>
public static class PermissionMiddlewareExtensions
{
    public static IApplicationBuilder UsePermissionMiddleware(this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<PermissionMiddleware>();
    }
} 